package edu.office.sessionRepository;

import edu.office.applicationRepository.QuestionRepository;
import edu.office.applicationRepository.StudenttestpaperRepository;
import edu.office.applicationRepository.TestpaperRepository;
import edu.office.applicationRepository.WrongquestionCollectionRepository;
import edu.office.entities.*;
import edu.office.tools.EOMessage;
import edu.office.tools.EOMessage1;
import edu.office.tools.PersonalSessionSetup;
import edu.office.tools.StaticFields;
import jakarta.enterprise.context.SessionScoped;
import jakarta.inject.Inject;
import jakarta.inject.Named;
import jakarta.servlet.http.Part;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.Serializable;
import java.nio.file.Files;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.*;

/**
 * @author 周鹏, MIU Ya-Nan
 */
@Named
@SessionScoped
public class HaveTest implements Serializable {

    private final String path1 = "studenttestpaper/";
    private final int maxSize = 1024000;
    @Inject
    StudenttestpaperRepository studentTestpaperController;
          @Inject
    WrongquestionCollectionRepository wrongquestionCollectionController;
    @Inject
    QuestionRepository applicationQuestionController;
    @Inject
    StudenttestpaperRepository applicationStudenttestpaperController;
    @Inject
    TestpaperRepository applicationTestpaper;
    @Inject
    PersonalSessionSetup personalSessionSetup;
       @Inject
    CommonSession commonSession;
    String temStudentAnswer;//往数据库testpaper中添加学生答案的字符串
    LocalDateTime startTime;
    //学生答案的URL，方便学生下载

    //Wrong questions ============end===========================
    //导出学生试卷==============================开始=================
    List<Question> testPaperQuestions = new LinkedList<>();

    //    //=======================计算时间================================
    private List<Question> testQuestions1;
    private int studentscore;
    private HashMap<Question, String> studentanswerHashMap;//试题id/学生答案
    //与上面的getNumber对应，主要用于多项填空题，与各个空的值进行绑定
    private List<String> data = new LinkedList<>();
    //下面处理多项选择题========================begin==========================
    private String[] studentAnswer4multi = {"", "", "", "", ""};
    //For subjective and objective program
    private Part answerPart;

    private int leftMinutes(Studenttestpaper studenttestpaper, boolean isSelfPractice) {
        if (isSelfPractice) {
            return 10;
        }
        Testpaper testpaper = applicationTestpaper.find("ID", studenttestpaper.getTESTPAPERID()).firstResult();
        //判断时间是否已用完
        int result = (int) (testpaper.getSPECIFIED_INTERVAL() - studenttestpaper.getANSWERED_INTERVAL() / 60000f);
        if (result < 0) {
            persistAnswer(studenttestpaper);
        }
        return result;
    }

    public boolean isTimeOver(boolean isSelfPractice, Studenttestpaper studenttestpaper) {
        if (isSelfPractice) {
            return false;
        }
        Testpaper testpaper = applicationTestpaper.find("ID", studenttestpaper.getTESTPAPERID()).firstResult();
        return testpaper.getSPECIFIED_INTERVAL() * 6000f - studenttestpaper.getANSWERED_INTERVAL() < 0;
    }

    public int getNumber(Question question) {//获得题目的“数目”特征
        return applicationQuestionController.getNumber(question);
    }

    ////////////
//=======================下一题 and 上一题================================
    public void nextQuesAfterFinished(Studenttestpaper studenttestpaper, Question currentQuestion, int wrongReason) {// 下一题
        //已经完成了试卷，正在检查错误原因
        //检查本题是否为错题，如果是，则
        if (studenttestpaper.getFIRST_WRONGQUESTIONIDS().contains(String.valueOf(currentQuestion.getID()))) {
            WrongquestionCollection wcc = new WrongquestionCollection();
            wcc.setQUESTION_ID(currentQuestion.getID());
            wcc.setREASON_ID(wrongReason);
            wcc.setSTUDENT_ID(studenttestpaper.getSTUDENT_ID());
            wrongquestionCollectionController.create(wcc);
        }
    }

    public void nextQuesInPorcess(Studenttestpaper studenttestpaper, Question currentQuestion, boolean isSelfPractice) {
        // 下一题
        //没有完成试卷，正在向后翻阅，这里暂且只处理了多项选择题，应该是所有题目的答案都在这里处理
        //处理做题时间
        int costTime = (int) Duration.between(LocalDateTime.now(), startTime).getSeconds();
        //保存学生做这道题所花的时间
        Questionstudentcosttime temQSC = new Questionstudentcosttime(currentQuestion.getID(), studenttestpaper.getSTUDENT_ID());
        temQSC.setCOSTTIME(costTime);
        temQSC.persist();
        studenttestpaper.setANSWERED_INTERVAL(studenttestpaper.getANSWERED_INTERVAL() + costTime);
        startTime = LocalDateTime.now();
        if (editorNot(studenttestpaper, isSelfPractice, studenttestpaper.getIndex(currentQuestion.getID()))) {
            persistAnswer(studenttestpaper);
        }

    }

    private boolean editorNot(Studenttestpaper studenttestpaper, boolean isSelfPractice, int myindex) {
        //每隔一段时间(StaticFields.QUESTIONANSWERINTERVAL)就保存到数据库中，以防断电或意外;
        //或者当已经完成全部题目时，保存到数据库
        //A decision tree
        if (leftMinutes(studenttestpaper, isSelfPractice) <= 0) {
            studenttestpaper.setFINISHED(true);
            return true;
        } else if (myindex % StaticFields.QUESTIONANSWERINTERVAL == 0) {
            return true;
        }
        return false;
    }

    private void persistAnswer(Studenttestpaper studenttestpaper) {
        String temStudentAnswer = "";
        for (Question q : testQuestions1) {
            if (null == getStudentanswerHashMap().get(q)) {
                System.out.println("没有答案");
            }
            temStudentAnswer += StaticFields.FIRSTDELIMITED + getStudentanswerHashMap().get(q);
        }
        studenttestpaper.setSTUDENT_ANSWER(temStudentAnswer);
    }

    public String getQuestionTitle(Question question, Student student) {
        String result = "";
        switch (question.getTYPE()) {
            case StaticFields.JUDGMENT:
            case StaticFields.MULTISELECTION:
            case StaticFields.SIMPLEANSWER:
            case StaticFields.SINGLEFILL:
            case StaticFields.SINGLESELECTION:
                //case StaticFields.MULTIFILL:
                result = question.getVALUEINFO();
                break;
            case StaticFields.OBJECTIVEPROGRMA:
            case StaticFields.SUBJECTIVEPROGRAM:
                result = question.getVALUEINFO().replaceAll(applicationQuestionController.SCHOOLNAMESTUDENTNAME,
                        "s" + student.getSCHOOL_ID() + student.getId());
                result = result.replaceAll(applicationQuestionController.STUDENTNAME, "s" + student.getId());
                break;
        }
        return result;
    }

    public int getStudentscore() {
        return studentscore;
    }

    public void setStudentscore(int studentscore) {
        this.studentscore = studentscore;
    }

    public int getLeftMinutes(Studenttestpaper studenttestpaper) {
        return applicationTestpaper.find("ID", studenttestpaper.getTESTPAPERID()).firstResult().getSPECIFIED_INTERVAL() - studenttestpaper.getANSWERED_INTERVAL() / 60000;
    }

    public String getStudentanswer(Question question) {
        return getStudentanswerHashMap().get(question);
    }

    public void setStudentanswer(String studentanswer, Question question) {
        //这道题的答案
        //除多项选择、编程和多个填空外，都可以在这里处理
        //把多余的空格替换掉
        studentanswer = StaticFields.replaceSpacewithOne(studentanswer);
        if (!getStudentanswerHashMap().getOrDefault(question, "").trim().equals(studentanswer)) {
            getStudentanswerHashMap().put(question, studentanswer);
        }
    }

    public String[] getStudentAnswer4multi(Question question) {
        //多个答案用逗号分隔
        if (null != getStudentanswerHashMap().get(question)) {
            String[] temStrings = getStudentanswerHashMap().get(question).split(",");
            //下面把学生的答案放里边，不足部分补空串
            int i = 0;
            for (; i < temStrings.length; i++) {
                studentAnswer4multi[i] = temStrings[i];
            }
            while (i < studentAnswer4multi.length) {
                studentAnswer4multi[i] = "";
                i++;
            }
        } else {
            studentAnswer4multi = new String[]{"", "", "", "", ""};
        }
        return studentAnswer4multi;
    }

    public void setStudentAnswer4multi(String[] studentAnswer4multi, Question question) {

        String result = "";
        if (studentAnswer4multi.length > 1) {
            for (int i = 0; i < studentAnswer4multi.length - 1; i++) {
                result += studentAnswer4multi[i] + ",";
            }
        }
        result += studentAnswer4multi[studentAnswer4multi.length - 1];

        result = StaticFields.replaceSpacewithOne(result);
        getStudentanswerHashMap().put(question, result);
        studentAnswer4multi = new String[]{"", "", "", "", ""};//为下一题做准备
    }

    public Studenttestpaper startSelfPractice(Student student, Subject subject) {//完成自测
        return applicationStudenttestpaperController.getTestpaper4leadPoint(student, subject);
    }

    public Studenttestpaper startSelfHomeworkPractice(Subject subject, Student student) {//完成自测作业
        HashSet<Studenttestpaper> feasibleTestpaper = applicationStudenttestpaperController.getStudentTestPaper(false, subject, student);
        return this.commonPractice(feasibleTestpaper, true, subject, student);
    }

    public Studenttestpaper machineDecide(Subject subject, Student student) {
       applicationTestpaper.creatTestpapersForStudent(true, student, subject);//Create new testpaper according to the leadpoint
        HashSet<Studenttestpaper> testpaper = applicationStudenttestpaperController.getStudentTestPaper(false, subject, student);
        return this.commonPractice(testpaper, true, subject, student);
    }

    public Studenttestpaper startHomework(Subject subject, Student student) {//
        // testpaperController.creatTestpapersForStudent();
        HashSet<Studenttestpaper> feasibleTestpaper = applicationStudenttestpaperController.getStudentTestPaper(false, subject, student);
        return this.commonPractice(feasibleTestpaper, false, subject, student);
    }

    /*
    @param create: 如果不存在，是否要生成
     */
    private Studenttestpaper commonPractice(HashSet<Studenttestpaper> feasibleTestpaper, boolean create, Subject subject, Student student) {
        Studenttestpaper studenttestpaper;
        if (feasibleTestpaper.isEmpty() && create) {
            //没有试卷，则生成试卷
            applicationTestpaper.creatTestpapersForStudent(false, student, subject);//No leadpoint are referenced
            feasibleTestpaper = applicationStudenttestpaperController.getStudentTestPaper(false, subject, student);
        }
        if (!feasibleTestpaper.isEmpty()) {
            studenttestpaper = feasibleTestpaper.iterator().next();
        } else {
            studenttestpaper = null;
        }
        prepareTestpaper(studenttestpaper);
        return studenttestpaper;
    }

    public String startExamination(Subject subject, Student student) {
        HashSet<Studenttestpaper> feasibleTestpaper = applicationStudenttestpaperController.getStudentTestPaper(true, subject, student);
        if (!feasibleTestpaper.isEmpty()) {
            Iterator it = feasibleTestpaper.iterator();
            int feasibleCount = 0;
            while (it.hasNext()) {
                Studenttestpaper testpaper1 = (Studenttestpaper) it.next();
                if (isInTestTime(testpaper1)) {
                    prepareTestpaper(testpaper1);
                    feasibleCount++;
                    break;
                }
            }

            if (feasibleCount <= 0) {
               return EOMessage.getEOMessageENUM(EOMessage1.Not)
                        + EOMessage.getEOMessageENUM(EOMessage1.Test)
                        + EOMessage.getEOMessageENUM(EOMessage1.Time);
            }
        } else {
            return EOMessage.getEOMessageENUM(EOMessage1.No)
                    +   EOMessage.getEOMessageENUM(EOMessage1.Testpaper);
        }
        return null;
    }

    private boolean isInTestTime(Studenttestpaper studenttestpaper) {
        boolean result = false;
        Calendar current = Calendar.getInstance();
        //把current改成UTC时间
        //int zoneoffset=current.get(Calendar.ZONE_OFFSET);
        //current.add(Calendar.MILLISECOND, zoneoffset);
        Testpaper testpaper=applicationTestpaper.find("ID",studenttestpaper.getTESTPAPERID()).firstResult();
        if (null == testpaper.getSTARTTIME() || null == testpaper.getENDTIME()) {
            return result;
        }
        //完成，下面可以对比了
        if (LocalDateTime.now().isBefore(testpaper.getSTARTTIME())) {
            result = false;
        } else {
            result = !LocalDateTime.now().isAfter(testpaper.getENDTIME());
        }
        return result;
    }

    public List<Question> getRegular(Studenttestpaper studenttestpaper) {
        List<Question> regularTP = applicationQuestionController.getTestQuestion(studenttestpaper);
        return regularTP;
    }

    private String prepareTestpaper(Studenttestpaper studenttestpaper) {
        if (null != studenttestpaper) {
            this.testQuestions1 = this.getRegular(studenttestpaper);
            setStudentanswerHashMap(new HashMap<>());
            testQuestions1.forEach(question1 -> {
                getStudentanswerHashMap().put(question1, "");
            });
            if (!studenttestpaper.getFINISHED()) {
                startTime = LocalDateTime.now();
            }
            return EOMessage.getEOMessageENUM(EOMessage1.Succeed);
        } else {
            return EOMessage.getEOMessageENUM(EOMessage1.No) + EOMessage.getEOMessageENUM(EOMessage1.Testpaper)
                    + EOMessage.getEOMessageENUM(EOMessage1.Or)
                    + EOMessage.getEOMessageENUM(EOMessage1.Practice);
        }
    }

    public int questionListSize() {
        return this.testQuestions1.size();
    }

    public String endPractice() {
        return null;
    }

    public HashMap<Question, String> getStudentanswerHashMap() {
        return studentanswerHashMap;
    }

    public void setStudentanswerHashMap(HashMap<Question, String> studentanswerHashMap) {
        this.studentanswerHashMap = studentanswerHashMap;
    }

    public void submit(Studenttestpaper studenttestpaper) {
        studenttestpaper.setFINISHED(true);
        this.persistAnswer(studenttestpaper);
        //为在内存中判卷，把学生答案直接传递过去。
        //???????????studentTestpaperController.setStudentanswerHashMap(studentanswerHashMap);
        //在finishedTest.xhmtl中调用了testpaperController.correctTestpaper();
        //保存学生完成各题的时间
    }

    public Part getAnswerPart(Studenttestpaper studenttestpaper) {
        //因为这道题是主观题，所以可能将会花较长时间，所以先保存以前的题目
        persistAnswer(studenttestpaper);
        return answerPart;
    }

    public String setAnswerPart(Part answerPart, Studenttestpaper studenttestpaper, Question question) {
        this.answerPart = answerPart;
        //1）以学生的登录＋题目名称作为新文件的；
        // 2)将学生的上舒心传上传到指定目录；
        if (null != answerPart) {
            try (InputStream input = answerPart.getInputStream()) {
                String fileName = answerPart.getSubmittedFileName();
                File fold = new File(personalSessionSetup.getFilePath() + "/" + this.path1 + studenttestpaper.getID());
                if (!fold.exists()) {
                    fold.mkdir();
                }
                fold = new File(personalSessionSetup.getFilePath() + "/" + this.path1 + studenttestpaper.getID() + "/" + question.getID() + "/");
                if (!fold.exists()) {
                    fold.mkdir();
                }
                File targetFile = new File(fold.getAbsolutePath() + "/" + fileName);
                if (targetFile.exists()) {
                    targetFile.delete();
                }
                Files.copy(input, new File(fold.getAbsolutePath(), fileName).toPath());
                return EOMessage.getEOMessageENUM(EOMessage1.Succeed);
            } catch (IOException e) {
                return EOMessage.getEOMessageENUM(EOMessage1.Failed);
            }
        }
        return "";
    }

    private HashSet<String> getProgramType(String programQuestionFileType) {//Only calculate once, but how to know the parameter is changed?
        HashSet<String> programFileType = new HashSet<>();
        String[] programType = programQuestionFileType.split(",");
        for (String type : programType) {
            programFileType.add(type);
        }
        return programFileType;
    }

    public String partValidator(Object value, Studenttestpaper studenttestpaper,Question question) {
        String message = "";
        Part file = (Part) value;
        if (null != value) {
            if (file.getSize() > maxSize) {
                return EOMessage.getEOMessageENUM(EOMessage1.Too_Big);
            } else {
                boolean infileType = false;
                try {
                    String loadfileType = file.getSubmittedFileName().substring(file.getSubmittedFileName().lastIndexOf(".") + 1);
                    for (String fileType : getProgramType("")) {//?????????原来是从页面拿的
                        if (loadfileType.equals(fileType)) {
                            infileType = true;
                            break;
                        }
                    }
                } catch (Exception e) {
                    System.out.println("HaveTest--partValidator");
                    infileType = false;
                }
                if (infileType) {//Persist the file
                    int costTime = (int) (Duration.between(LocalDateTime.now(),startTime).getSeconds());
                    studenttestpaper.setANSWERED_INTERVAL(studenttestpaper.getANSWERED_INTERVAL() + costTime);
                    //这道题的答案
                    //Except multi-Selection and programing, all the answer can be dealt with here
                    //把多余,的空格替换掉
                    String studentanswer = file.getSubmittedFileName();
//                    if (!getStudentanswerHashMap().getOrDefault(currentQuestion, "").trim().equals(studentanswer)) {
//                        getStudentanswerHashMap().put(currentQuestion, studentanswer);
//                    }
                    getStudentanswerHashMap().put(question, studentanswer);
//                    setAnswerPart(file);
                    startTime = LocalDateTime.now();
                } else {
                    message = EOMessage.getEOMessageENUM(EOMessage1.Not)
                            + EOMessage.getEOMessageENUM(EOMessage1.Valid)
                            + EOMessage.getEOMessageENUM(EOMessage1.File)
                            + EOMessage.getEOMessageENUM(EOMessage1.Type);
                }
            }
        }
        return message;
    }
    public List<Question> getTestQuestion(Studenttestpaper temTestpaper) {
        if (testPaperQuestions.isEmpty()) {
            testPaperQuestions = applicationQuestionController.getTestQuestion(temTestpaper);
        }
        return testPaperQuestions;
    }

    public String nextStudentsTestpaper() {
        testPaperQuestions.clear();
        return "========================";
    }

}
